home *** CD-ROM | disk | FTP | other *** search
- page 58,132
- .286c
- .MODEL LARGE
-
- ;**********************************************************************
- ;* *
- ;* Equates *
- ;* *
- ;**********************************************************************
-
- tccount equ 72 ;reload count to produce 16572 Hz
- countmax_18hz equ 910 ;ratio of new timer rate to old rate
-
- tcaddrc equ 43h ;timer/counter control register address
- tcaddrd equ 40h ;timer/counter data register zero
-
- tcmode equ 34h ;mode control byte for timer/counter
-
- ppiaddr equ 61h ;programmable peripheral interface address
-
- ;**********************************************************************
- ;* *
- ;* Macros *
- ;* *
- ;**********************************************************************
-
- ljz macro dest
- local skip
- jnz skip
- jmp dest
- skip:
- endm
-
- ;**********************************************************************
- ;* *
- ;* Global variables *
- ;* *
- ;**********************************************************************
-
- .DATA
- even ;don't put these on an odd boundary
-
- blockaddr dd 0 ;beginning of memory block
- blocksize dd 0 ;size of memory block
- blockend dd 0 ;last address of memory block + 1
- currentaddr dd 0 ;pointer to current record position in memory
- datacount dd 0 ;number of data bytes already recorded
- fwrtaddr dd 0 ;address of next byte to be written to disk
- fwrtcount dd 0 ;number of bytes already written to disk
-
- goflag dw 0 ;indicates whether recording is in progress
- fileflag dw 0 ;indicates whether data is written to a file
- filehandle dw 0 ;handle of file to receive voice data
- hookedflag dw 0 ;indicates whether the interrupt is hooked
- countfor_18hz dw 0 ;counter to determine when to call BIOS
- comaddr dw 0 ;the address of the COM port
-
- comlist dw 3FEh ;needed addresses of all COM ports
- dw 2FEh
- dw 3EEh
- dw 2EEh
-
- shiftcount db 0 ;current bit position within byte
-
- ;**********************************************************************
- ;* *
- ;* Code *
- ;* *
- ;**********************************************************************
-
- .CODE
-
- bios_timer_routine dd 0 ;we keep this in the code segment
- ; for access through the CS register
- ; since the other segment registers
- ; will contain unknown values when
- ; this is needed
-
- assume ds:DGROUP
-
- ;**********************************************************************
- ;* Speed up the timer tick and set "goflag" *
- ;**********************************************************************
-
- startvoice proc near
-
- pushf
- cli
- mov al,tcmode
- out tcaddrc,al
- mov ax,tccount
- out tcaddrd,al
- mov al,ah
- out tcaddrd,al
- mov shiftcount,0
- mov countfor_18hz,countmax_18hz
- mov goflag,1
- popf
- ret
-
- startvoice endp
-
- ;**********************************************************************
- ;* Slow the timer tick to normal and clear "goflag" *
- ;**********************************************************************
-
- stopvoice proc near
-
- pushf
- cli
- mov al,tcmode
- out tcaddrc,al
- mov al,0
- out tcaddrd,al
- out tcaddrd,al
- mov goflag,0
- popf
- ret
-
- stopvoice endp
-
- ;**********************************************************************
- ;* Interrupt service routine *
- ;**********************************************************************
-
- timer_tick proc far
-
- push ds
- push bx
- push es
- push ax
- push cx
- push dx
-
- mov ax,DGROUP
- mov ds,ax
-
- cmp goflag,0
- je chain_exit
-
- les bx,currentaddr
- mov ah,es:[bx]
- mov dx,comaddr
- in al,dx
- rcl al,4
- rcl ah,1
- mov es:[bx],ah
-
- inc shiftcount
- and shiftcount,07h
- jnz exit_decide
-
- mov ax,es
- inc bx
- jnz check_wrap
- add ax,1000h
- check_wrap:
- cmp bx,word ptr blockend
- jne save_cur_addr
- cmp ax,word ptr blockend+2
- jne save_cur_addr
- mov bx,word ptr blockaddr
- mov ax,word ptr blockaddr+2
- save_cur_addr:
- mov word ptr currentaddr,bx
- mov word ptr currentaddr+2,ax
- add word ptr datacount,1
- adc word ptr datacount+2,0
-
- exit_decide:
- dec countfor_18hz
- jnz nochain_exit
- mov countfor_18hz,countmax_18hz
-
- chain_exit:
- pop dx
- pop cx
- pop ax
- pop es
- pop bx
- pop ds
- jmp cs:bios_timer_routine
-
- nochain_exit:
- mov al,20h
- out 20h,al
- pop dx
- pop cx
- pop ax
- pop es
- pop bx
- pop ds
- iret
-
- timer_tick endp
-
- ;**********************************************************************
- ;* Initialization procedure *
- ;**********************************************************************
-
- ;This routine should be called exactly one time before any of the other
- ; routines in this package are called. It takes no parameters, but returns
- ; a value indicating success or failure as follows:
-
- ;Return value Meaning
- ;------------ -------
- ; 0 success
- ; 1 voice package already initialized
- ; 2 wrong CPU, won't run on 8088 or 8086
-
- public RVOICE_INIT
-
- RVOICE_INIT proc far
-
- push sp
- pop ax
- cmp ax,sp
- je vi_test
- mov ax,2
- ret
-
- vi_test:
- cmp hookedflag,0
- je vi_hook
- mov ax,1
- ret
-
- vi_hook:
- enter 0,0
- push si
- push di
-
- push ds
- lea dx,RVOICE_CBREAK
- mov ax,seg RVOICE_CBREAK
- mov ds,ax
- mov ax,2523h
- int 21h
- pop ds
-
- push ds
- mov ax,3508h
- int 21h
- mov word ptr cs:bios_timer_routine,bx
- mov word ptr cs:bios_timer_routine+2,es
- lea dx,timer_tick
- mov ax,seg timer_tick
- mov ds,ax
- mov ax,2508h
- int 21h
- pop ds
-
- pop di
- pop si
- mov hookedflag,1
- sub ax,ax
- leave
- ret
-
- RVOICE_INIT endp
-
- ;**********************************************************************
- ;* Cleanup procedure *
- ;**********************************************************************
-
- ;This will restore the interrupt 8 vector to its original state. This
- ; routine MUST be called before the main program exits to DOS, unless:
- ; (a) the program has never called RVOICE_INIT, or (b) the program is
- ; becoming memory-resident.
-
- ;There are no parameters. The return values are 0 for success or 1 if
- ; the interrupt vector was not in fact hooked.
-
- public RVOICE_CLEANUP
-
- RVOICE_CLEANUP proc far
-
- cmp hookedflag,1
- je vc_unhook
- mov ax,1
- ret
-
- vc_unhook:
- enter 0,0
- push si
- push di
- call stopvoice
- push ds
- lds dx,cs:bios_timer_routine
- mov ax,2508h
- int 21h
- pop ds
- pop di
- pop si
- mov hookedflag,0
- sub ax,ax
- leave
- ret
-
- RVOICE_CLEANUP endp
-
- ;**********************************************************************
- ;* Vector restore for Control-Break *
- ;**********************************************************************
-
- public RVOICE_CBREAK
-
- RVOICE_CBREAK proc far
-
- pusha
- push ds
- push es
-
- mov ax,DGROUP
- mov ds,ax
- call stopvoice
- call RVOICE_CLEANUP
-
- pop es
- pop ds
- popa
- stc
- ret
-
- RVOICE_CBREAK endp
-
- ;**********************************************************************
- ;* "File write catch-up" procedure *
- ;**********************************************************************
-
- ;This must be called frequently from the main program if file writing is
- ; being used and the length of the data to be recorded is longer than the
- ; length of the memory block. The routine checks the progress of the
- ; address pointer in use by the interrupt service routine and writes
- ; new data to the file as it becomes available.
-
- ;There are no parameters. The return values are 0 for success 1 if there
- ; was no new data to write, or 2 if an error occurred while writing the file.
-
- vcat_temp1l equ [bp-4] ;current address from ISR
- vcat_temp1h equ [bp-2]
- vcat_temp2l equ [bp-8] ;<unused>
- vcat_temp2h equ [bp-6]
-
- ;the three stopping points:
-
- vcat_temp3l equ [bp-12] ;current address - fill address
- vcat_temp3h equ [bp-10]
- vcat_temp4l equ [bp-16] ;block end - fill address
- vcat_temp4h equ [bp-14]
- vcat_temp5l equ [bp-20] ;(boundary) - fill address
- vcat_temp5h equ [bp-18]
-
- vcat_templength equ 20
-
- public RVOICE_CATCHUP
-
- RVOICE_CATCHUP proc far
-
- enter vcat_templength,0
-
- ;should we even be doing this?
-
- cmp fileflag,0
- ljz vcat_exit0
-
- ;grab a stable value from currentaddr
- ; since it is changing all the time
-
- cli
- mov ax,word ptr currentaddr
- mov vcat_temp1l,ax
- mov ax,word ptr currentaddr+2
- mov vcat_temp1h,ax
- sti
-
- ;calculate the forward distance to each of the
- ; three possible stopping points
-
- vcat_getgap:
- mov ax,vcat_temp1l
- sub ax,word ptr fwrtaddr
- mov vcat_temp3l,ax
- pushf
- mov ax,vcat_temp1h
- sub ax,word ptr fwrtaddr+2
- sar ax,12
- popf
- sbb ax,0
- mov vcat_temp3h,ax
-
- vcat_getclearance:
- mov ax,word ptr blockend
- sub ax,word ptr fwrtaddr
- mov vcat_temp4l,ax
- pushf
- mov ax,word ptr blockend+2
- sub ax,word ptr fwrtaddr+2
- sar ax,12
- popf
- sbb ax,0
- mov vcat_temp4h,ax
-
- mov ax,word ptr fwrtaddr
- neg ax
- mov vcat_temp5l,ax
- mov word ptr vcat_temp5h,0
- jnz vcat_cmp2
- inc word ptr vcat_temp5h
-
- ;select the stopping point which will be
- ; encountered soonest
-
- ;Since we are not interested in the negative
- ; values, doing unsigned compares in a search
- ; for the smallest number will give the
- ; desired result.
-
- vcat_cmp2:
- mov ax,vcat_temp3h
- mov cx,vcat_temp3l
-
-
- vcat_cmp3:
- cmp ax,vcat_temp4h
- jb vcat_cmp5
- ja vcat_cmp4
- cmp cx,vcat_temp4l
- jb vcat_cmp5
-
- vcat_cmp4:
- mov ax,vcat_temp4h
- mov cx,vcat_temp4l
-
-
- vcat_cmp5:
- cmp ax,vcat_temp5h
- jb vcat_cmp7
- ja vcat_cmp6
- cmp cx,vcat_temp5l
- jb vcat_cmp7
-
- vcat_cmp6:
- mov ax,vcat_temp5h
- mov cx,vcat_temp5l
-
-
- vcat_cmp7:
-
- ;Now the smallest number is in AX:CX.
- ; However, AX:CX may be 65536 or 0FFFFh
- ; (illegal), so we must test for these
- ; possibilities.
-
- cmp ax,1
- je vcat_fixcx
- cmp cx,0FFFFh
- jne vcat_writefile
-
- vcat_fixcx:
- mov cx,0FE00h
-
- vcat_writefile:
- or cx,cx
- jz vcat_exit1
- mov bx,filehandle
- push ds
- lds dx,fwrtaddr
- mov ah,40h
- int 21h
- pop ds
- jc vcat_error2
- cmp ax,cx
- jne vcat_error2
-
- ;update global varibles to show the current
- ; situation
-
- add word ptr fwrtcount,cx
- adc word ptr fwrtcount+2,0
-
- add word ptr fwrtaddr,cx
- jnc vcat_fillwrap
- add word ptr fwrtaddr+2,1000h
-
- vcat_fillwrap:
- mov bx,word ptr blockend
- cmp bx,word ptr fwrtaddr
- jne vcat_exit0
- mov ax,word ptr blockend+2
- cmp ax,word ptr fwrtaddr+2
- jne vcat_exit0
- mov bx,word ptr blockaddr
- mov ax,word ptr blockaddr+2
- mov word ptr fwrtaddr,bx
- mov word ptr fwrtaddr+2,ax
-
- jmp short vcat_exit0
-
- ;return code exit points
-
- vcat_error2:
- mov ax,2
- jmp short vcat_exit
-
- vcat_exit1:
- mov ax,1
- jmp short vcat_exit
-
- ;normal exit point
-
- vcat_exit0:
-
- ;don't leave until at least one bit has been played
- ; if goflag is not zero
-
- mov ax,word ptr currentaddr
- cmp vcat_temp1l,ax
- jne vcat_exitloop
- cmp goflag,0
- jne vcat_exit0
- vcat_exitloop:
- sub ax,ax
- vcat_exit:
- leave
- ret
-
- RVOICE_CATCHUP endp
-
- ;**********************************************************************
- ;* "Start recording" procedure *
- ;**********************************************************************
-
- ;Accepts the following parameters with PASCAL parameter-passing convention:
-
- ;Position Size Description
- ;-------- ---- -----------
- ; 1 4 A far pointer to the memory block used for voice data.
- ; 2 4 A dword indicating the length of the memory block.
- ; 3 2 A flag word. If this is 1, then data will be written to
- ; a file. If it is 0, no file operations will be performed.
- ; 4 2 An open file handle. This is ignored if the flag word
- ; is 0.
- ; 5 2 A word containing the number of the COM port to be used
- ; for input (1 thru 4).
- ; 6 4 A dword indicating the offset within the memory block
- ; where recording is to begin.
-
- ;Return value Meaning
- ;------------ -------
- ; 0 success
- ; 1 block size is too small (blocklen < 8192 and
- ; file write = yes)
- ; 2 voice recording is already in progress
- ; 3 a COM port number not within the range of 1 thru 4
- ; was specified
- ; 4 starting position is not less than block length
-
- min_blocksize equ 8192
-
- vs_parm1 equ [bp+20] ;length = 4
- vs_parm2 equ [bp+16] ;length = 4
- vs_parm3 equ [bp+14] ;length = 2
- vs_parm4 equ [bp+12] ;length = 2
- vs_parm5 equ [bp+10] ;length = 2
- vs_parm6 equ [bp+6] ;length = 4
-
- vs_parmlength equ 18
-
- public RVOICE_START
-
- RVOICE_START proc far
-
- cmp goflag,0
- je vs_begin
- mov ax,2
- ret vs_parmlength
-
- vs_begin:
- enter 0,0
- mov word ptr datacount,0
- mov word ptr datacount+2,0
- mov word ptr fwrtcount,0
- mov word ptr fwrtcount+2,0
-
- les bx,dword ptr vs_parm1
- mov word ptr blockaddr,bx
- mov word ptr blockaddr+2,es
- les bx,dword ptr vs_parm6
- mov ax,es
- add bx,word ptr blockaddr
- adc ax,0
- shl ax,12
- add ax,word ptr blockaddr+2
- mov word ptr currentaddr,bx
- mov word ptr currentaddr+2,ax
- mov word ptr fwrtaddr,bx
- mov word ptr fwrtaddr+2,ax
- les bx,dword ptr vs_parm2
- mov word ptr blocksize,bx
- mov word ptr blocksize+2,es
- mov ax,es
- add bx,word ptr blockaddr
- adc ax,0
- shl ax,12
- add ax,word ptr blockaddr+2
- mov word ptr blockend,bx
- mov word ptr blockend+2,ax
- cmp ax,word ptr currentaddr+2
- jb vs_error4
- ja vs_gethandle
- cmp bx,word ptr currentaddr
- jbe vs_error4
-
- vs_gethandle:
- mov ax,vs_parm4
- mov filehandle,ax
-
- mov bx,vs_parm5
- cmp bx,1
- jb vs_error3
- cmp bx,4
- ja vs_error3
- dec bx
- shl bx,1
- lea ax,comlist
- add bx,ax
- mov ax,[bx]
- mov comaddr,ax
-
- mov ax,vs_parm3
- mov fileflag,ax
-
- or ax,ax
- jz vs_exit0
-
- mov ax,word ptr blocksize
- sub ax,min_blocksize
- mov ax,word ptr blocksize+2
- sbb ax,0
- jnc vs_exit0
- mov ax,1
- jmp short vs_exit
-
- vs_error3:
- mov ax,3
- jmp short vs_exit
-
- vs_error4:
- mov ax,4
- jmp short vs_exit
-
- vs_exit0:
- call startvoice
- sub ax,ax
- vs_exit:
- leave
- ret vs_parmlength
-
- RVOICE_START endp
-
- ;**********************************************************************
- ;* "Stop recording" procedure *
- ;**********************************************************************
-
- ;Call this to stop the voice recording operation.
-
- ;This routine accepts no parameters and has no return information.
-
- public RVOICE_STOP
-
- RVOICE_STOP proc far
-
- call stopvoice
- sub ax,ax
- ret
-
- RVOICE_STOP endp
-
- ;**********************************************************************
- ;* "Get status" procedure *
- ;**********************************************************************
-
- ;This will report the status of voice operations.
-
- ;The first parameter is a far pointer to a dword which will receive the
- ; number of bytes which have already been recorded.
- ;The second parameter is a far pointer to a dword which will receive a
- ; value indicating the offset within the memory block of the next byte
- ; to be filled by the recording operation.
-
- ;There is no return value.
-
- vst_parm1 equ [bp+10] ;length = 4
- vst_parm2 equ [bp+6] ;length = 4
-
- vst_parmlength equ 8
-
- public RVOICE_STATUS
-
- RVOICE_STATUS proc far
-
- enter 0,0
-
- les bx,vst_parm1
- cli
- mov ax,word ptr datacount
- mov dx,word ptr datacount+2
- mov es:[bx],ax
- mov es:[bx+2],dx
- les bx,vst_parm2
- mov ax,word ptr currentaddr
- mov dx,word ptr currentaddr+2
- sti
- shr dx,12 ;we can cheat here because we
- ; know it's incremented by 1000h units
- mov cx,word ptr blockaddr+2
- shr cx,12
- sub ax,word ptr blockaddr
- sbb dx,cx
- mov es:[bx],ax
- mov es:[bx+2],dx
-
- sub ax,ax
- leave
- ret vst_parmlength
-
- RVOICE_STATUS endp
-
- end
-